﻿using System.Drawing;
using System.Collections.Generic;
using System.Windows.Forms;
namespace CubeCalculations
{
   public class CubeVisualizer : PictureBox
   {
      private Cubex cube;
      public Cubex Cube
      {
         get { return cube; }
         set
         {
            if (cube == value)
               return;

            cube = value;

            if(value==null)
               return;

            cube.OnCubeChanged += cube_OnCubeChanged;
            CubeGetSides = new GetCubeSide[]
                               {
                                  cube.GetTop,
                                  cube.GetLeft,
                                  cube.GetFront,
                                  cube.GetRight,
                                  cube.GetBack,
                                  cube.GetBottom
                               };
            CubeSetSides = new SetCubeSide[]
                               {
                                  cube.SetTop,
                                  cube.SetLeft,
                                  cube.SetFront,
                                  cube.SetRight,
                                  cube.SetBack,
                                  cube.SetBottom
                               };
         }
      }

      void cube_OnCubeChanged(object sender, System.EventArgs e)
      {
         if (!LayoutSuspended)
         Refresh();
      }

      private Color[] cubeColors = new Color[6];
                                      //{
                                      //   Color.Red,
                                      //   Color.Green,
                                      //   Color.Yellow,
                                      //   Color.Blue,
                                      //   Color.White,
                                      //   Color.Orange
                                      //};
      public Color ColorTop
      {
         get { return cubeColors[(int)CubeSides.Top]; }
         set
         {
            cubeColors[(int)CubeSides.Top] = value;
            Refresh();
         }
      }
      public Color ColorLeft
      {
         get { return cubeColors[(int)CubeSides.Left]; }
         set
         {
            cubeColors[(int)CubeSides.Left] = value;
            Refresh();
         }
      }
      public Color ColorFront
      {
         get { return cubeColors[(int)CubeSides.Front]; }
         set
         {
            cubeColors[(int)CubeSides.Front] = value;
            Refresh();
         }
      }
      public Color ColorRight
      {
         get { return cubeColors[(int)CubeSides.Right]; }
         set
         {
            cubeColors[(int)CubeSides.Right] = value;
            Refresh();
         }
      }
      public Color ColorBack
      {
         get { return cubeColors[(int)CubeSides.Back]; }
         set
         {
            cubeColors[(int)CubeSides.Back] = value;
            Refresh();
         }
      }
      public Color ColorBottom
      {
         get { return cubeColors[(int)CubeSides.Bottom]; }
         set
         {
            cubeColors[(int)CubeSides.Bottom] = value;
            Refresh();
         }
      }
      public Color[] CubeColors
      {
         get { return cubeColors; }
         set
         {
            cubeColors = value;
            Refresh();
         }
      }

      private int selectedSide;
      public int SelectedSide
      {
         get { return selectedSide; }
         set
         {
            if (value < 1 || value > 6)
            {
               return;
            }
            selectedSide = value;
         }
      }

      private delegate int[] GetCubeSide();
      private delegate void SetCubeSide(int[] Values);

      private GetCubeSide[] CubeGetSides;
      private SetCubeSide[] CubeSetSides;

      const int RectWidthSpace = 22;
      const int SideSpace = 2;
      const int RectWidth = 20;

      private Rectangle[] Cubie;
      private bool CubieInitialized = false;

      public CubeVisualizer()
      {
         Size = MinimumSize = MaximumSize = CalcSize();
         Cubie = new Rectangle[9*6];
         LayoutSuspended = false;
         selectedSide = 1;
         cubeColors = new Color[6];
      }

      private bool layoutSuspended;
      public bool LayoutSuspended
      {
         get { return layoutSuspended; }
         set
         {
            layoutSuspended = value; 
            if (!value)
               Refresh();
         }
      }

      protected override void OnPaint(PaintEventArgs pe)
      {
         base.OnPaint(pe);
         pe.Graphics.DrawImageUnscaled(VisualizeCube(),0,0);
      }
      protected override void OnSizeChanged(System.EventArgs e)
      {
         Size = MinimumSize = MaximumSize = CalcSize();
      }
      
      Size CalcSize()
      {
         return new Size((RectWidthSpace) * 12 + 3 * SideSpace, (RectWidthSpace) * 9 + 2 * SideSpace);
      }

      private Bitmap bmp;
      Bitmap VisualizeCube()
      {
         if(bmp == null)
           bmp = new Bitmap((RectWidthSpace) * 12 + 3 * SideSpace, (RectWidthSpace) * 9 + 2 * SideSpace);
         Graphics g = Graphics.FromImage(bmp);
        g.FillRectangle(new SolidBrush(BackColor), new Rectangle(new Point(0,0), CalcSize()));
         
         if(cube == null)
         {
            //string NullString = "Cube is zwei";
            //var CubeFont = new Font("Microsoft Sans Serif", 16F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            //SizeF StringSize = g.MeasureString(NullString, CubeFont);
            //g.DrawString(NullString, CubeFont, Brushes.Black, (((float)bmp.Width) - StringSize.Width) / 2, (((float)bmp.Height) - StringSize.Height) / 2);
            return bmp;
         }


         int xOffset = 0,yOffset = 0;
         int[] Values=null;
         for (int i = 0; i < 6; i++)
         {
            Values = CubeGetSides[i]();
            switch (i)
            {
               case 0:
                  xOffset = 3 * RectWidthSpace + SideSpace;
                  yOffset = 0;
                  break;
               case 1:
                  xOffset = 0;
                  yOffset = 3 * RectWidthSpace + SideSpace;
                  break;
               case 2:
                  xOffset = 3 * RectWidthSpace + SideSpace;
                  yOffset = 3 * RectWidthSpace + SideSpace;
                  break;
               case 3:
                  xOffset = 6 * RectWidthSpace + 2 * SideSpace;
                  yOffset = 3 * RectWidthSpace + SideSpace;
                  break;
               case 4:
                  xOffset = 9 * RectWidthSpace + 3 * SideSpace;
                  yOffset = 3 * RectWidthSpace + SideSpace;
                  break;
               case 5:
                  xOffset = 3 * RectWidthSpace + SideSpace;
                  yOffset = 6 * RectWidthSpace + 2 * SideSpace;
                  break;
            }

            if (Values != null)
               for (int j = 0; j < Values.Length; j++)
               {
                  DrawRectangle(g, xOffset + (j % 3) * RectWidthSpace, yOffset + (j - (j % 3)) / 3 * RectWidthSpace, RectWidth, cubeColors[Values[j] - 1], i, j);
               }
         }

         return bmp;
      }
      void DrawRectangle(Graphics g, int x, int y, int width, Color c, int i, int j)
      {
         if (!CubieInitialized)
         {
            Cubie[i*9 + j] = new Rectangle(x, y, width, width);
            if(i*9+j == Cubie.Length)
               CubieInitialized = true;
         }
         g.FillRectangle(new SolidBrush(c), x, y, width, width);
         g.DrawRectangle(Pens.Black, x, y, width - 1, width - 1);
      }
      protected override void OnMouseClick(MouseEventArgs e)
      {
         base.OnMouseClick(e);
         var cRect = new Rectangle(e.Location, new Size(1, 1));
         for(int i = 0;i<Cubie.Length;i++)
         {
            if(Cubie[i].IntersectsWith(cRect))
            {
               var CubeDelIdx = (i - (i%9))/9;
               var CubeIdx = i%9;
               var cCube = CubeGetSides[CubeDelIdx]();
               cCube[CubeIdx] = selectedSide;
               CubeSetSides[CubeDelIdx](cCube);
               return;
            }
         }
      }
   }
}
